//
//                 librtmeus.cpp: written by T.Yoshikai 2010/05/26
//
#include "librtmeus.h"

RTMEus* rtmeusp[MAXRTMEUS];
int connectedrtm=0;
std::string retbuf;

int init_rtm(char* host, int port, int man_no)
{
    rtmeusp[connectedrtm] = new RTMEus(host, port, man_no);
    connectedrtm++;
    
    return (connectedrtm-1);
}

void exit_rtm(void)
{
    for(int i=0;i<connectedrtm;i++) delete rtmeusp[i];
    connectedrtm=0;
    exit(0);
}

int load_module(int rtmno, char* sopath, char* initfuncname)
{
    int ret;
    struct stat st;

    ret=stat(sopath, &st);
    if(ret!=0){
      std::cerr << sopath << ": No such file!" << std::endl;
        return -1;
    }
    
    rtmeusp[rtmno]->LoadModule((const char*)sopath, (const char*)initfuncname);
    
    return 0;
}

int create_component(int rtmno, char* classname, char* instancename, double exec_rate, char* exec_type, int stateflag)
{
    bool sflag;
    if(stateflag) sflag=true;
    else sflag=false;    
    return rtmeusp[rtmno]->CreateComponent((const char*)classname, (const char*)instancename, exec_rate, (const char*)exec_type, sflag);
}

int resolve_component(int rtmno, char* searchpath, char* instancename, int stateflag)
{
    bool sflag;
    if(stateflag) sflag=true;
    else sflag=false;    
    return rtmeusp[rtmno]->ResolveComponent((const char*)searchpath, (const char*)instancename, sflag);
}

int find_component(int rtmno, char* searchpath, char* instancename)
{
    return rtmeusp[rtmno]->FindComponent((const char*)searchpath, (const char*)instancename);
}

const char* get_componentname(int rtmno, int component_no)
{
    RTMEusComp *tgtcomp;
    
    tgtcomp = rtmeusp[rtmno]->GetComponent(component_no);  
    
    return tgtcomp->GetComponentName().c_str();
}

int activate_component(int rtmno, int component_no)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    comp->Activate();
    
    return 0;
}

int deactivate_component(int rtmno, int component_no)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    comp->Deactivate();
    
    return 0;    
}

int set_configuration(int rtmno, int component_no, char* configvar, char* config)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    comp->SetConfiguration((const char*)configvar, (const char* )config);
    
    return 0;        
}

int destroy(int rtmno, int component_no)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    comp->Destroy();

    return 0;    
}

int show_component_info(int rtmno, int component_no, int showlevel)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    comp->ShowComponentInfo(showlevel);
    
    return 0;    
}

int inputdata_to_component(int rtmno, int component_no, char* portname, char* datatype, char* data)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    comp->InputData((const char*)portname, (const char*)datatype, (const char*)data);
    
    return 0;        
}

const char* receivedata_from_component(int rtmno, int component_no, char* portname, char* datatype)
{
    RTMEusComp* comp;

    comp = rtmeusp[rtmno]->GetComponent(component_no);
    retbuf = comp->ReceiveData((const char*)portname, datatype);
    
    return retbuf.c_str();
}

const char* sendcommand_to_component(int rtmno, int component_no, char* command, char* argv)
{
    RTMEusComp *tgtcomp;
    const char *tmpstr;
    char tgtcomppath[256];
        
    tgtcomp = rtmeusp[rtmno]->GetComponent(component_no);  
    tmpstr = tgtcomp->GetComponentPath().c_str();
    strncpy(tgtcomppath, tmpstr, strlen(tmpstr));
    tgtcomppath[strlen(tmpstr)]='\0';
    
    //send command
    retbuf = rtmeusp[rtmno]->SendCommandService((const char*)tgtcomppath, (const char*)command, (const char*)argv);

    return retbuf.c_str();
}

std::string make_eusreturn_strings(char* src)
{
    std::stringstream ss;
    char* token;
    int typeno=-1;

    token = strtok(src, " ");
    if(token!=NULL){
        if(strncmp(token, "c", 1)==0){
            typeno=0;
            ss << "#i(";
        } else if(strncmp(token, "s", 1)==0){
            typeno=1;
            ss << "#i(";
        } else if(strncmp(token, "l", 1)==0){
            typeno=2;
            ss << "#i(";
        } else if(strncmp(token, "f", 1)==0){
            typeno=3;
            ss << "#f(";
        } else if(strncmp(token, "d", 1)==0){
            typeno=4;
            ss << "#f(";
        } else return "Invalid state type!";
    } else return "Invalid state name!";
        
    while((token = strtok(NULL, " "))!=NULL)
    {
        switch(typeno){
        case 0://char
            ss << token << " ";
            break;
        case 1://short
        case 2://long
            ss << atoi(token) << " ";
            break;
        case 3:
        case 4:
            ss << (float)atof(token) << " ";
            break;
        }
    }

    ss << ")";

    return ss.str();
}
const char* getstates_from_component(int rtmno, int component_no, char* namelist)
{
    std::stringstream ss;
    std::string tmpbuf;
    RTMEusComp *tgtcomp;
    std::vector<std::string> stateres;
    std::vector<std::string> names;

    tgtcomp = rtmeusp[rtmno]->GetComponent(component_no);  

    //namelist is like "statea stateb statec"
    names = coil::split(std::string(namelist), " ");
        
    //send 'get states'
    tmpbuf = tgtcomp->GetStates(names);
    if(strcmp(tmpbuf.c_str(), "nil")==0) return "No such state!";
    
    //devide result
    stateres = coil::split(tmpbuf, ",");

    for(unsigned int i=0;i<stateres.size();i++){
        if((stateres.size() > 1) && (i == 0)) ss << "(";
        ss << make_eusreturn_strings((char*)stateres[i].c_str());
        if(stateres.size() > 1) ss << " ";
    }
    if(stateres.size() > 1) ss << ")";

    retbuf = ss.str();
    
    return retbuf.c_str();
}
const char* setstates_to_component(int rtmno, int component_no, char* namelist, char* valuelist)
{
    coil::Properties pp;
    std::vector<std::string> names;
    std::vector<std::string> values;
    RTMEusComp *tgtcomp;

    tgtcomp = rtmeusp[rtmno]->GetComponent(component_no);  
    
    //namelist is like "statea stateb statec"
    names = coil::split(std::string(namelist), " ");
    //valuelist is like "f 1.0 2.0 3.0, s 1 2 3"
    values = coil::split(std::string(valuelist), ",");
    
    for(unsigned int i=0;i<names.size();i++){
        std::vector<std::string> tvalue;
        std::string key;
        tvalue = coil::split(values[i], " ");

        key = names[i] + std::string(".type");
        std::string val;
        if(strncmp(tvalue[0].c_str(), "c", 1)==0) val = std::string("CHARSEQ");
        else if(strncmp(tvalue[0].c_str(), "s", 1)==0) val = std::string("SHORTSEQ");
        else if(strncmp(tvalue[0].c_str(), "l", 1)==0) val = std::string("LONGSEQ");
        else if(strncmp(tvalue[0].c_str(), "f", 1)==0) val = std::string("FLOATSEQ");
        else if(strncmp(tvalue[0].c_str(), "d", 1)==0) val = std::string("DOUBLESEQ");
        
        pp.setProperty(key, val);
        
        for(unsigned int j=0;j<tvalue.size()-1;j++){
            std::ostringstream ss;
            ss << j;
            key = names[i] + std::string(".data.axis") + ss.str();
            pp.setProperty(key , "");
            key = names[i] + std::string(".data.axis") + ss.str() + std::string(".value");
            pp.setProperty(key , tvalue[j+1]);
        }
    }

    retbuf = tgtcomp->SetStates(pp);
    
    return retbuf.c_str();
}

void set_plugin_mode(int rtmno, int leader_component_no, int attatched_component_num, int* attatched_component_nos)
{
    char lcompname[128];
    std::vector<std::string> acompnames;
    RTMEusComp *lcomp;
    const char *tmpstr;
        
    lcomp = rtmeusp[rtmno]->GetComponent(leader_component_no);  
    tmpstr = lcomp->GetComponentName().c_str();
    strncpy(lcompname, tmpstr, strlen(tmpstr));
    lcompname[strlen(tmpstr)]='\0';

    for(int i=0;i<attatched_component_num;i++){
        RTMEusComp *comp;
        comp = rtmeusp[rtmno]->GetComponent(attatched_component_nos[i]);  
        acompnames.push_back(comp->GetComponentName());
    }
        
    rtmeusp[rtmno]->SetPluginMode(lcompname, acompnames);
}

void plugin_mode_allactivate(int rtmno, int leader_component_no, int attatched_component_num, int* attatched_component_nos, int interval)
{
    char lcompname[128];
    std::vector<std::string> acompnames;
    RTMEusComp *lcomp;
    const char *tmpstr;
        
    lcomp = rtmeusp[rtmno]->GetComponent(leader_component_no);  
    tmpstr = lcomp->GetComponentName().c_str();
    strncpy(lcompname, tmpstr, strlen(tmpstr));
    lcompname[strlen(tmpstr)]='\0';

    for(int i=0;i<attatched_component_num;i++){
        RTMEusComp *comp;
        comp = rtmeusp[rtmno]->GetComponent(attatched_component_nos[i]);  
        acompnames.push_back(comp->GetComponentName());
    }
    
    rtmeusp[rtmno]->PluginModeAllActivate(lcompname, acompnames, interval);
}

void plugin_mode_alldeactivate(int rtmno, int leader_component_no, int attatched_component_num, int* attatched_component_nos)
{
    char lcompname[128];
    std::vector<std::string> acompnames;
    RTMEusComp *lcomp;
    const char *tmpstr;
        
    lcomp = rtmeusp[rtmno]->GetComponent(leader_component_no);  
    tmpstr = lcomp->GetComponentName().c_str();
    strncpy(lcompname, tmpstr, strlen(tmpstr));
    lcompname[strlen(tmpstr)]='\0';

    for(int i=0;i<attatched_component_num;i++){
        RTMEusComp *comp;
        comp = rtmeusp[rtmno]->GetComponent(attatched_component_nos[i]);  
        acompnames.push_back(comp->GetComponentName());
    }
    
    rtmeusp[rtmno]->PluginModeAllDeactivate(lcompname, acompnames);
}

int connect_components(int out_rtmno, int out_component_no, char* out_portname, int in_rtmno, int in_component_no, char* in_portname, int subscriptiontype)
{
    char outcomppath[128], incomppath[128];
    RTMEusComp *out_comp, *in_comp;

    in_comp = rtmeusp[in_rtmno]->GetComponent(in_component_no);
    strcpy(incomppath, (char*)(in_comp->GetComponentPath().c_str()));
    
    out_comp = rtmeusp[out_rtmno]->GetComponent(out_component_no);
    strcpy(outcomppath, (char*)(out_comp->GetComponentPath().c_str()));
    
    RTMEus::ConnectComponents((const char*)outcomppath,(const char*)out_portname, (const char*)incomppath, (const char*) in_portname, subscriptiontype);

    return 0;
}

int disconnect_components(int out_rtmno, int out_component_no, char* out_portname, int in_rtmno, int in_component_no, char* in_portname)
{
    const char *outcomppath, *incomppath;
    RTMEusComp *out_comp, *in_comp;

    in_comp = rtmeusp[in_rtmno]->GetComponent(in_component_no);
    incomppath = (const char*)(in_comp->GetComponentPath().c_str());
    
    out_comp = rtmeusp[out_rtmno]->GetComponent(out_component_no);
    outcomppath = (const char*)(out_comp->GetComponentPath().c_str());
    
    RTMEus::DisconnectComponents((const char*)outcomppath,(const char*)out_portname, (const char*)incomppath, (const char*) in_portname);    
    
    return 0;    
}
